﻿using System;
using System.Collections.Generic;
using System.Linq;


namespace Qetza.TeamFoundation.WorkItemQuery.Admin
{
    /// <summary>
    /// Represents the help command.
    /// </summary>
    public class CommandHelp : ICommand
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="CommandHelp"/> class with the specified 
        /// command container.
        /// </summary>
        /// <param name="container">
        /// The command container.
        /// </param>
        /// <param name="validator">
        /// A parameter validator to get help syntax.
        /// </param>
        public CommandHelp(ICommandContainer container, IParameterValidator validator)
        {
            // validate parameters
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }

            if (validator == null)
            {
                throw new ArgumentNullException("parameterValidator");
            }

            // set properties
            this.CommandContainer = container;
            this.ParameterValidator = validator;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the command container.
        /// </summary>
        /// <value>
        /// The command container.
        /// </value>
        public ICommandContainer CommandContainer { get; private set; }

        /// <summary>
        /// Gets the parameter validator.
        /// </summary>
        /// <value>
        /// The parameter validator.
        /// </value>
        public IParameterValidator ParameterValidator { get; private set; }

        #endregion

        #region ICommand Members

        /// <inheritdoc />
        public string Name
        {
            get { return "help"; }
        }

        /// <inheritdoc />
        public string HelpText
        {
            get { return ResourceStrings.HelpCommandHelpText; }
        }

        /// <inheritdoc />
        public IEnumerable<ParameterInfo> AllowedParameters
        {
            get
            {
                return new[] { 
                    new ParameterInfo() { 
                        Name = ResourceStrings.CommandArgument, 
                        IsFlag = true,
                        HelpText = ResourceStrings.CommandHelpText
                        } 
                    }; 
            }
        }

        /// <inheritdoc />
        public void Execute(IDictionary<string, string> parameters)
        {
            Utility.WriteWrappedLines(ResourceStrings.Banner);

            if (parameters.Count == 0)
            {
                this.DisplayGenericHelp();
            }
            else
            {
                this.DisplaySpecificHelp(parameters.Keys.First());
            }
        }

        /// <inheritdoc />
        public void ValidateParameters(IDictionary<string, string> parameters)
        {
            return;
        }

        #endregion

        #region Private Helpers

        // Displays the generic help text.
        private void DisplayGenericHelp()
        {
            // write header
            Console.WriteLine();
            Utility.WriteWrappedLines(string.Format(ResourceStrings.HelpGenericText, Utility.ToolName));
            Console.WriteLine();

            // write command list
            foreach (var command in this.CommandContainer.RegisteredCommands.OrderBy(c => c.Name))
            {
                Console.Write("\t");
                Console.WriteLine(command.Name);
            }
        }

        // Displays help on a specific command.
        private void DisplaySpecificHelp(string commandName)
        {
            // check command name
            var command = this.CommandContainer.RegisteredCommands.FirstOrDefault(c => c.Name == commandName);
            if (command == null)
            {
                throw new InvalidParameterException(
                    string.Format(ResourceStrings.UnknownCommand, commandName, Utility.ToolName)
                    );
            }

            // write command help
            Console.WriteLine();
            Utility.WriteWrappedLines(command.HelpText);
            Console.WriteLine();
            Utility.WriteWrappedLines(
                string.Format(
                    "Usage: {0} {1} {2}",
                    Utility.ToolName,
                    command.Name,
                    this.ParameterValidator.GetSyntax(command.AllowedParameters)
                    )
                );

            Console.WriteLine();

            // write command parameters help
            var maxParameterNameLength = command.AllowedParameters.Max(pi => pi.Name.Length);
            foreach (var param in command.AllowedParameters)
            {
                this.WriteHelpText(param.Name, param.HelpText, maxParameterNameLength + 5);
            }
        }

        // Writes help text for a command parameter.
        private void WriteHelpText(string parameterName, string helpText, int leftPadding)
        {
            var firstLine = true;
            var paddingStr = string.Empty.PadLeft(leftPadding);

            foreach (var line in helpText.Break(Console.BufferWidth - paddingStr.Length - 1))
            {
                if (firstLine)
                {
                    Console.Write(" " + parameterName);
                    Console.Write(string.Empty.PadLeft(paddingStr.Length - parameterName.Length - 1));
                    Console.WriteLine(line);

                    firstLine = false;
                }
                else
                {
                    Console.WriteLine(paddingStr + line);
                }
            }
        }

        #endregion
    }
}
